
package Server;

import CLIENT.Client;
import CLIENT.Message;
import GUI.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.DefaultListModel;
import java.util.Date;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.border.BevelBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

/**
 * This Class Handles all the Main Chat Panel functionalities and the GUI For Main Chat
 * @author Yaniv Kalif
 */

public class ServerMainChatPanel extends JPanel implements MouseListener,ActionListener,KeyListener,ListSelectionListener
{
   LinkedList<PrivateChatFrame> _PrivateChatFrameList = new LinkedList<PrivateChatFrame>();
    JTextArea _textArea; // The Text Area for the main chat (everyones messages)
    JScrollPane text_Scroll;//the scroller for the main chat area
     JList _userList;//displays the users list
    DefaultListModel listModel;//the actually list of the users
    JScrollPane user_scroll;//the scroller for user list
    JTextArea _messageField;//the message field
    JScrollPane mess_Scroll;//the scroller for the message field
    EmoticonsPanel _Emoticons;//the EmoticonsPanel panel
    JButton _send,_history;//the "send" button& history button
    Font _font;//the main Font
    Color _TA_Color;//The Text Areas color
    Color _BG_Color;//The Background color
    Image _image3DP;
    Image _image3DP_red;
    Image _image3DP_run;
    Image _imagetitle;
    //**********************************************//
    //***********Initialize Arguments Network****************//
    Client[] _clientSockets = new Client[100];
    int _ConnectedClients_num=0;
    NewClientsListenerThread _serverlistener;
    Client _client; // represents this server details (name+socket)
    ObjectOutputStream[] _out = new ObjectOutputStream[100];

    String folderPath = System.getProperty("user.dir");
    File  logFile;
    /**
     * constructor for MainChatPanel
     * This contructor:
     * * setting the images
     * * setting the colors
     * * initializing: users list , TextArea , EmoticonsPanel Panel, Message Field and the "send" button
     */
    public ServerMainChatPanel(ServerSocket socket,String Nickname)
    {
        //Setting the Layout Manager
            setLayout(null);

        //Set the Image
            _image3DP = Toolkit.getDefaultToolkit().getImage("Pics/3D Postman.gif");
            _image3DP_red = Toolkit.getDefaultToolkit().getImage("Pics/3D Postman with large red.gif");
            _image3DP_run = Toolkit.getDefaultToolkit().getImage("Pics/3D Postman running copy.gif");
            _imagetitle = Toolkit.getDefaultToolkit().getImage("Pics/talk2me.gif");
        //Create/Set Colors
            _TA_Color=new Color(152, 251, 152);//create TextArea color
            _BG_Color=new Color(60,179,113);//create BG color
            this.setBackground(_BG_Color);

         //Initialize Font
            _font=new Font("Arial",Font.BOLD,13);
           //initialize model list
            listModel = new DefaultListModel();
            listModel.addElement(Nickname);

         //initialize List
                _userList=new JList(listModel);
                _userList.setVisibleRowCount(20);
                _userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);//make sure you can choose only one user at one time
                _userList.setLayoutOrientation(0);// VERTICAL
                _userList.setBackground(_TA_Color);
                _userList.setFont(_font);
                _userList.setToolTipText("Choose one user to enter a Private chat Window");
                _userList.setDragEnabled(true);
                _userList.addListSelectionListener(this);
                user_scroll=new JScrollPane(_userList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                user_scroll.setBorder(new TitledBorder(new BevelBorder(BevelBorder.LOWERED),"Users List"));//set the border for the user scroller+title
                this.add(user_scroll);
                user_scroll.setBounds(200, 150, 150, 400);
                
        //Initialize TextArea
                _textArea = new JTextArea();
                _textArea.setFont(_font);
                _textArea.setBackground(_TA_Color);
                _textArea.setEditable(false);
                _textArea.setToolTipText("Main Chat - Here you'll see all the messages in the community");
                text_Scroll=new JScrollPane(_textArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                text_Scroll.setBounds(350, 150, 600, 400);
                text_Scroll.setBorder(new TitledBorder(new BevelBorder(BevelBorder.LOWERED),"Main Chat"));//set the border for the text scroller+title
                this.add(text_Scroll);

        //initialize EmoticonsPanel(Panel)
            _Emoticons=new EmoticonsPanel();
            _Emoticons.setBounds(350, 550, 350, 30);
            for(int i=0;i<_Emoticons._size;i++)
            _Emoticons._Buttons[i].addMouseListener(this);
            this.add(_Emoticons);

        //initialize message field
            _messageField=new JTextArea("Enter your message here . . .");
            _messageField.setFont(_font);
            _messageField.setToolTipText("Enter Your Message Here . . .");
            _messageField.setColumns(50);
            mess_Scroll=new JScrollPane(_messageField, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            mess_Scroll.setBounds(350, 585, 500, 50);
            _messageField.setBorder(new BevelBorder(BevelBorder.LOWERED));
            _messageField.addKeyListener(this);
            this.add(mess_Scroll);

        //initialize "send" button
            _send=new JButton("SEND");
            _send.setBounds(850, 585,100,50);
            _send.addMouseListener(this);
            _send.addActionListener(this);
            _send.setBorder(new BevelBorder(BevelBorder.RAISED));
            this.add(_send);
         //initialize "history" button
             _history=new JButton("HISTORY");
            _history.setBounds(950, 150,100,50);
            _history.addMouseListener(this);
            _history.addActionListener(this);
            _history.setBorder(new BevelBorder(BevelBorder.RAISED));
            this.add(_history);

       //initialize new server listener (for clients)
            _serverlistener = new NewClientsListenerThread(socket, this);
            Thread T=new Thread(_serverlistener); // listen to new clients ( THREAD)
            T.start();

            _client = new Client(Nickname,null);

            //initialize log file
            logFile = new File(folderPath + "\\History "+_client.GetName()+".txt");//the path to the history file
    }
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        //draw the images
            g.drawImage(_image3DP, -70, -20, null);
            g.drawImage(_image3DP_run, 130 , 550, null);
            g.drawImage(_image3DP_red, 950, 300, null);
            g.drawImage(_imagetitle, 300, -40, null);

        // Specify the current users in the program to the users list
//            _userList.setModel(new javax.swing.AbstractListModel()
//                            {
//                            String[] strings = { "Yaniv kalif", "Karin Seyag", "Avi Cohen"};
//                            public int getSize() { return strings.length; }
//                            public Object getElementAt(int i) { return strings[i]; }
//                            });

        //paint the color of the panel and he's components by the colors of the theme
            this.setBackground(_BG_Color);
            _textArea.setBackground(_TA_Color);
            _userList.setBackground(_TA_Color);
            _messageField.setBackground(_TA_Color);
            text_Scroll.setBackground(_TA_Color);
            user_scroll.setBackground(_TA_Color);
            
    }
    /**
 * this function changes the "theme" of the panel by changing the BackGroung color and the TextArea color
 * @param BG the new Background color
 * @param TA the new TextArea color
 */
    public void ChangeTheme(Color BG,Color TA)
    {
        if(BG==Color.black)
            _imagetitle = Toolkit.getDefaultToolkit().getImage("Pics/talk2me opp.gif");
        else
            _imagetitle = Toolkit.getDefaultToolkit().getImage("Pics/talk2me.gif");

        _TA_Color=TA;
        _BG_Color=BG;
        repaint();
    }
    /**
     * This inherited function handles events on emoticons buttons
     * @param e MouseEvent that accured
     */
    public void mouseClicked(MouseEvent e) // handle events on emoticons buttons
    {
        String s=_messageField.getText();
        _messageField.setText(null);

        //EmoticonsPanel events
                if(e.getSource()==_Emoticons._Buttons[0])//happy
                {
                    _messageField.insert(s+":-)",0);
                }
                if(e.getSource()==_Emoticons._Buttons[1])//sad
                {
                    _messageField.insert(s+":-(",0);
                }
                if(e.getSource()==_Emoticons._Buttons[2])//wink
                {
                    _messageField.insert(s+";-)",0);
                }
                if(e.getSource()==_Emoticons._Buttons[3])//angry
                {
                    _messageField.insert(s+">:(",0);
                }
                  if(e.getSource()==_Emoticons._Buttons[4])//XD
                {
                    _messageField.insert(s+":XD",0);
                }
             if(e.getSource()==_Emoticons._Buttons[5])//confused
                {
                    _messageField.insert(s+":s",0);
                }
        if(e.getSource()==_Emoticons._Buttons[6])//frown
                {
                    _messageField.insert(s+":- -(",0);
                }
        if(e.getSource()==_Emoticons._Buttons[7])//lol
                {
                    _messageField.insert(s+"^^)",0);
                }
        if(e.getSource()==_Emoticons._Buttons[8])//biggrin
                {
                    _messageField.insert(s+":-|",0);
                }
        if(e.getSource()==_Emoticons._Buttons[9])//neutral
                {
                    _messageField.insert(s+":|",0);
                }
        if(e.getSource()==_Emoticons._Buttons[10])//oh
                {
                    _messageField.insert(s+":-O",0);
                }
        if(e.getSource()==_Emoticons._Buttons[11])//teeth
                {
                    _messageField.insert(s+":-D",0);
                }
        if(e.getSource()==_Emoticons._Buttons[12])//winktongue
                {
                    _messageField.insert(s+":P",0);
                }

        
    }
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) { }
    public void mouseEntered(MouseEvent e) {  }
    public void mouseExited(MouseEvent e) {    }
    /**
     * This inherited function handles events on "send" Button & "history" button
     * @param e ActionEvent that accured
     */
    public void actionPerformed(ActionEvent e)
    {
        //"send" pressed
                if(e.getSource()==_send)
                {
            try {
                String s = _messageField.getText();
                _messageField.setText(null);
                try {
                    SendMessage(_client, s, null);
                } catch (UnknownHostException ex) {
                    Logger.getLogger(ServerMainChatPanel.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ServerMainChatPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println("The server is sending:" + s);
            } catch (IOException ex) {
                Logger.getLogger(ServerMainChatPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
                }
                 //"history" pressed
                if(e.getSource()==_history)
                {
                    LoadFile(logFile);
                }

    }
    /**
     * This inherited function handles eyboard events
     * @param e Keyboard Event that accured
     */
     public void keyPressed(KeyEvent e)//conects the "enter" key to the "send" button
    {
        if(KeyStroke.getKeyStrokeForEvent(e)==KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0))
        {
            this.actionPerformed(new ActionEvent(_send, 0, null));
        }
    }
    public void keyTyped(KeyEvent e){}
    public void keyReleased(KeyEvent e) {}

    /**
     * this function accurs every time an action on the _userList happens
     * the function will open a new private window
     * @param e ListSelectionEvent that accured
     */
    public void valueChanged(ListSelectionEvent e)
    {
        int index = 0;
       
                //********** private chat event ************//
                    Object s=_userList.getSelectedValue();
                    if(s!=null)
                    {
                        for (int i=0; i<_ConnectedClients_num;i++)
                        {
                            if(_clientSockets[i].GetName() == s)
                                index = i;
                        }
                        PrivateChatFrame _p = new PrivateChatFrame((String) s, _out[index], _client);
                        _p.setVisible(true);
                        _PrivateChatFrameList.add(_p);
                    }

    }
    /**
     * This method add's a new client to the clients list
     * @param c - the new client
     * @throws IOException
     */
    public void AddClient(Client c) throws IOException
    {
        _clientSockets[_ConnectedClients_num]=c;
        _out[_ConnectedClients_num] = new ObjectOutputStream(_clientSockets[_ConnectedClients_num].GetSocket().getOutputStream());
        _ConnectedClients_num++;

        //update all the users that theres a new _client
    }
      /**
       * This method removes a client fron the list
       * @param c - the client that will be removed
       */
    public void RemoveClient(Client c) //TEMPORARY - NEEDS TO BE MORE PROFESSIONAL
    {
        for(int i=0;i<_ConnectedClients_num;i++)
        {
            if(_clientSockets[i] == c)
            {
                for (int j = 0; j < listModel.getSize(); j++)
                {
                    // Find the user to remove in the list and remove user
                    if (_clientSockets[i].GetName().equalsIgnoreCase(listModel.getElementAt(j).toString()))
                    {
                        listModel.remove(j);
                    }
                }

                _clientSockets[i] = null;
                
                UpdateClientsList();
            }

        }
    }
    /**
     * This method sends a message to the other users and save it into history file
     * @param c - the sender client
     * @param msg - the message to send
     * @param dst - the destination for the message
     * @throws IOException
     * @throws UnknownHostException
     * @throws InterruptedException
     */
    public void SendMessage(Client c,String msg, String dst ) throws IOException, UnknownHostException, InterruptedException// throws IOException
    {
        Message m = new Message(msg,c.GetName());
        m.SetClientsrc(c.GetName());
        m.SetClientdst(dst);

        if (m.GetClientdst()==null)
        {
            //enter the message to the TextBox
             Calendar cal=Calendar.getInstance();
             String time="("+cal.get(Calendar.HOUR_OF_DAY)+":"+cal.get(Calendar.MINUTE)+":"+cal.get(Calendar.SECOND)+")";
             String all=_textArea.getText();
             _textArea.setText(all+c.GetName()+time+" :\n\t"+msg+"\n");



             //save send messages to history file
             DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
             String fullTime = dateFormat.format(new Date());
             fullTime = dateFormat.format(new Date());
             String msgToFile = fullTime +" " + c.GetName() + " SAID : " + msg;
             SaveHistory(logFile, msgToFile); //save the massage into file
             Toolkit.getDefaultToolkit().beep();


            //sending the message to all the users
            for(int i=0;i<_ConnectedClients_num;i++)
            {
                try {
                if(_clientSockets[i].GetSocket() == c.GetSocket()/* || _client == c*/)//if it's the sender or the server itself
                {
                    continue;
                }
                    System.out.println("The server is sending");
                    _out[i].writeObject(m);
                    _out[i].flush();

                } catch (IOException ex) {
                    Logger.getLogger(ServerMainChatPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        else // if it's a private message
         {
             for(int j=0;j<_ConnectedClients_num;j++) // personal message
             {
                         if (m.GetClientdst().equals(_clientSockets[j].GetName()))
                         //if (m.GetClientdst()==_clientSockets[j].GetName())
                         {
                            try {
                                System.out.println("The server is sending");
                                _out[j].writeObject(m);
                                _out[j].flush();
                            } catch (IOException ex) {
                                Logger.getLogger(ServerMainChatPanel.class.getName()).log(Level.SEVERE, null, ex);
                            }
                         }
             }

             if(_client.GetName().equals(m.GetClientdst()))//The private message is for the server
             {
                    boolean flag = false;
                    for(int i=0;i<_PrivateChatFrameList.size();i++)
                    {
                        if(_PrivateChatFrameList.get(i).GetChatWith().equals(m.GetClientsrc()))
                        {
                            _PrivateChatFrameList.get(i).GetPrivateChatP().RecieveMessage(m);
                            flag = true;
                        }
                    }
                    if(flag==false)//if it's a new private chat
                    {
                        PrivateChatFrame p;
                        int index=-1;
                        for(int i=0;i<_ConnectedClients_num;i++)
                        {
                            if(_clientSockets[i].GetName().equals(m.GetClientsrc()))
                            {
                                index=i;
                            }
                        }
                        p = new PrivateChatFrame(m.GetClientsrc(),_out[index], _client);
                        p.setVisible(true);
                        _PrivateChatFrameList.add(p);
                        p.GetPrivateChatP().RecieveMessage(m);
                    }
             }
             
         }
    }
    /**
     * This methos recieves a message and send it to the right destination (private or general)
     * @param c - the sender client
     * @param msg - the message
     * @throws IOException
     * @throws UnknownHostException
     * @throws InterruptedException
     */
    public void RecieveMessage(Client c,String msg) throws IOException, UnknownHostException, InterruptedException
    {
        SendMessage(c,msg, null);// send the message to all the users

         //save recieved messages to history file
        DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        String fullTime = dateFormat.format(new Date());
        fullTime = dateFormat.format(new Date());
        String msgToFile = fullTime +" " + c.GetName() + " SAID : " + msg;
        SaveHistory(logFile, msgToFile); //save the massage into file
    }
    /**
     * This method saves a message to the history file
     * @param selectedFile - the history file
     * @param msg - the message to save
     */
    private void SaveHistory(File selectedFile , String msg)
    {
            String _in;
            try{
                    BufferedWriter fileWriter =  new BufferedWriter(new FileWriter(selectedFile, true));
                    _in = msg;
                    fileWriter.write(_in); //Write out the specfied string to the file
                    fileWriter.newLine(); //download one line between each point
                    fileWriter.flush(); //flushes and closes the stream
                    fileWriter.close();
            }

        catch(IOException e)
        {
            System.out.println("There was a problem:" + e);
        }
    }
    private void LoadFile(File fileToLoad)
    {
        // Load file
        String fileNameToLoad = fileToLoad.getPath();
        BufferedReader br = null;
        String bufLine = null;

        try {

            br= new BufferedReader(new FileReader(fileToLoad));
            String allText=_textArea.getText();
            _textArea.setText(allText + "************* HISTORY *************" + "\n");
            while (br.ready())
            {
                //read one line at the time from the save file
                bufLine= br.readLine();
                allText=_textArea.getText();
                _textArea.setText(allText + bufLine + "\n");
                bufLine=null;
            }
            allText=_textArea.getText();
            _textArea.setText(allText + "************* END HISTORY *************" + "\n");
        }
             catch (FileNotFoundException x) {
                x.printStackTrace();}
        catch (IOException x) {
                x.printStackTrace();
        }

    }
/**
 * Thid method adds a client to the users list
 * @param userName - the new userName
 */
    void AddClientToUsersList(String userName) {

        //add _client to the users list
        listModel.addElement(userName);
        repaint();
    }
/**
 * This method sends an update message to all the connected users about the users list
 */
    void UpdateClientsList() {

        // Create message
        String msg = "@";
        for(int i=0;i<_ConnectedClients_num + 1;i++) // +1 - Server
        {
            msg += listModel.getElementAt(i).toString() + ";";
        }

        // Send message to all users
        //sending the message to all the users
        for(int i=0;i<_ConnectedClients_num;i++)
        {
            try {
                System.out.println("The server is sending users list");

                Message m = new Message(msg,_clientSockets[0].GetName());
                m.SetClientdst(_clientSockets[i].GetName());
                m.SetisSystemMessage(true);

                _out[i].writeObject(m);
                _out[i].flush();

            } catch (IOException ex) {
                Logger.getLogger(ServerMainChatPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    public void CLOSEALL() throws IOException
    {
        for(int i=0;i<_ConnectedClients_num;i++)
            _clientSockets[i].GetSocket().close();

        _serverlistener.socket.close();
    }
}
